1 /*
2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021
3 License:   [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the CC BY-4.0 License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://creativecommons.org/licenses/by/4.0/
10 */
11 module hip.hiprenderer.backend.gl.glshader;
12 version(GLES30)
13 {
14     enum shaderVersion = "#version 300 es";
15     enum floatPrecision = "precision mediump float;";
16     // enum floatPrecision = "";
17 }
18 else version(GLES20)
19 {
20     enum shaderVersion = "#version 100";
21     enum floatPrecision = "precision mediump float;";
22 }
23 else
24 {
25     enum shaderVersion = "#version 330 core";
26     enum floatPrecision = "";
27 }
28 
29 version(OpenGL):
30 import hip.api.renderer.texture;
31 import hip.hiprenderer.backend.gl.glrenderer;
32 import hip.hiprenderer.shader;
33 import hip.hiprenderer.renderer;
34 import hip.hiprenderer.shader.shadervar;
35 import hip.util.conv;
36 import hip.util.format: fastUnsafeCTFEFormat, format;
37 import hip.error.handler;
38 
39 
40 
41 class Hip_GL3_FragmentShader : FragmentShader
42 {
43     uint shader;
44     private static string getBaseFragment()
45     {
46         __gshared string baseShader;
47         if(baseShader is null)
48         {
49             string defs;
50             version(WebAssembly) defs~= "#define WASM\n";
51             version(PSVita) defs~= "#define PSVITA\n";
52             baseShader = shaderVersion~"\n"~floatPrecision~"\n"~defs ~ getTexture2DDefine;
53             
54         }
55         return baseShader;
56     }
57     private static string getTexture2DDefine()
58     {
59         return 
60 `#ifdef WASM
61     #define TEXTURE_2D texture2D
62 #elif defined(PSVITA)
63     #define TEXTURE_2D texture2D
64 #else
65     #define TEXTURE_2D texture
66 #endif`;
67     }
68     override final string getDefaultFragment()
69     {
70         return getBaseFragment~q{
71             
72             uniform vec4 globalColor;
73             in vec4 vertexColor;
74             in vec2 tex_uv;
75             uniform sampler2D tex1;
76             out vec4 outPixelColor;
77 
78             void main()
79             {
80                 outPixelColor = vertexColor*globalColor*TEXTURE_2D(tex1, tex_uv);
81             }
82         };
83     }
84     override final string getFrameBufferFragment()
85     {
86         return getBaseFragment~q{
87 
88             in vec2 inTexST;
89             uniform sampler2D uBufferTexture;
90             uniform vec4 uColor;
91             out vec4 outPixelColor;
92 
93             void main()
94             {
95                 vec4 col = TEXTURE_2D(uBufferTexture, inTexST);
96                 float grey = (col.r+col.g+col.b)/3.0;
97                 outPixelColor = grey * uColor;
98             }
99         };
100     }
101 
102     version(GLES20) //They are very different, so, better to keep them separate
103     {
104         override final string getSpriteBatchFragment()
105         {
106             int sup = HipRenderer.getMaxSupportedShaderTextures();
107             string textureSlotSwitchCase;
108             if(sup == 1) textureSlotSwitchCase = "gl_FragColor = TEXTURE_2D(uTex[0], inTexST)*inVertexColor*uBatchColor;\n";
109             else
110             {
111                 for(int i = 0; i < sup; i++)
112                 {
113                     string strI = to!string(i);
114                     if(i != 0)
115                         textureSlotSwitchCase~="\t\t\t\telse ";
116                     textureSlotSwitchCase~="if(texId == "~strI~")"~
117                     "{gl_FragColor = TEXTURE_2D(uTex["~strI~"], inTexST)*inVertexColor*uBatchColor;}\n";
118                 }
119             }
120             textureSlotSwitchCase~="}\n";
121             enum shaderSource = q{
122                 uniform vec4 uBatchColor;
123 
124                 varying vec4 inVertexColor;
125                 varying vec2 inTexST;
126                 varying float inTexID;
127 
128                 void main()
129             };
130 
131 
132             return getBaseFragment~format!q{
133                     uniform sampler2D uTex[%s];}(sup)~
134                 shaderSource~
135             "{"~q{
136                     int texId = int(inTexID);
137             }~ textureSlotSwitchCase;
138         }
139     }
140     else
141     {
142         override final string getSpriteBatchFragment()
143         {
144             int sup = HipRenderer.getMaxSupportedShaderTextures();
145             //Push the line breaks for easier debugging on gpu debugger
146             string textureSlotSwitchCase = "switch(texId)\n{\n"; 
147             for(int i = 0; i < sup; i++)
148             {
149                 string strI = to!string(i);
150                 textureSlotSwitchCase~="case "~strI~": "~
151                 "\t\toutPixelColor = TEXTURE_2D(uTex["~strI~"], inTexST)*inVertexColor*uBatchColor;break;\n";
152             }
153             textureSlotSwitchCase~="}\n";
154 
155                 enum shaderSource = q{
156 
157                     uniform vec4 uBatchColor;
158 
159                     in vec4 inVertexColor;
160                     in vec2 inTexST;
161                     in float inTexID;
162 
163                     out vec4 outPixelColor;
164                     void main()
165                 };
166             return getBaseFragment~format!q{
167                     uniform sampler2D uTex[%s];}(sup)~
168                 shaderSource~
169             "{"~q{
170                     int texId = int(inTexID);
171             } ~textureSlotSwitchCase~
172             "}";
173             // outPixelColor = texture(uTex[texId], inTexST)* inVertexColor * uBatchColor;
174             // outPixelColor = vec4(texId, texId, texId, 1.0)* inVertexColor * uBatchColor;
175         }
176 
177     }
178 
179 
180     override final string getGeometryBatchFragment()
181     {
182         version(GLES20)
183         {
184             enum attr1 = q{varying};
185             enum outputPixelVar = q{};
186             enum outputAssignment = q{gl_FragColor};
187         }
188         else
189         {
190             enum attr1 = q{in};
191             enum outputPixelVar = q{out vec4 outPixelColor;};
192             enum outputAssignment = q{outPixelColor};
193         }
194         enum shaderSource = q{
195             uniform vec4 uGlobalColor;
196             %s vec4 inVertexColor;
197             %s
198 
199             void main()
200             {
201                 %s = inVertexColor * uGlobalColor;
202             }
203         }.fastUnsafeCTFEFormat(attr1, outputPixelVar, outputAssignment);
204         return getBaseFragment~shaderSource;
205     }
206 
207     override final string getBitmapTextFragment()
208     {
209         version(GLES20)
210         {
211             enum attr1 = q{varying};
212             enum outputPixelVar = q{};
213             enum outputAssignment = q{gl_FragColor};
214         }
215         else
216         {
217             enum attr1 = q{in};
218             enum outputPixelVar = q{out vec4 outPixelColor;};
219             enum outputAssignment = q{outPixelColor};
220         }
221         enum shaderSource = q{
222             
223 
224             uniform vec4 uColor;
225             uniform sampler2D uTex;
226             %s vec2 inTexST;
227             %s
228 
229             void main()
230             {
231                 float r = TEXTURE_2D(uTex, inTexST).r;
232                 %s = vec4(r,r,r,r)*uColor;
233             }
234         }.fastUnsafeCTFEFormat(attr1, outputPixelVar, outputAssignment);
235         return getBaseFragment~shaderSource;
236     }
237 }
238 class Hip_GL3_VertexShader : VertexShader
239 {
240     uint shader;
241 
242     override final string getDefaultVertex()
243     {
244         return shaderVersion~"\n"~floatPrecision~"\n"~q{
245             
246             layout (location = 0) in vec3 position;
247             layout (location = 1) in vec4 color;
248             layout (location = 2) in vec2 texCoord;
249             uniform mat4 proj;
250 
251 
252             out vec4 vertexColor;
253             out vec2 tex_uv;
254 
255             void main()
256             {
257                 gl_Position = proj*vec4(position, 1.0);
258                 vertexColor = color;
259                 tex_uv = texCoord;
260             }
261         };
262     }
263     override final string getFrameBufferVertex()
264     {
265         return shaderVersion~"\n"~floatPrecision~"\n"~q{
266             
267             layout (location = 0) in vec2 vPosition;
268             layout (location = 1) in vec2 vTexST;
269 
270             out vec2 inTexST;
271 
272             void main()
273             {
274                 gl_Position = vec4(vPosition, 0.0, 1.0);
275                 inTexST = vTexST;
276             }
277         };
278     }
279     override final string getSpriteBatchVertex()
280     {
281         version(GLES20) //`in` representation in GLES 20 is `attribute``
282         {
283             enum attr1 = q{attribute};
284             enum attr2 = q{attribute};
285             enum attr3 = q{attribute};
286             enum attr4 = q{attribute};
287             enum out1 = q{varying};
288             enum out2 = q{varying};
289             enum out3 = q{varying};
290         }
291         else
292         {
293             enum attr1 = q{layout (location = 0) in};
294             enum attr2 = q{layout (location = 1) in};
295             enum attr3 = q{layout (location = 2) in};
296             enum attr4 = q{layout (location = 3) in};
297             enum out1 = q{out};
298             enum out2 = q{out};
299             enum out3 = q{out};
300         }
301         enum shaderSource = q{
302             %s vec3 vPosition;
303             %s vec4 vColor;
304             %s vec2 vTexST;
305             %s float vTexID;
306 
307             uniform mat4 uProj;
308             uniform mat4 uModel;
309             uniform mat4 uView;
310             
311             %s vec4 inVertexColor;
312             %s vec2 inTexST;
313             %s float inTexID;
314 
315             void main()
316             {
317                 gl_Position = uProj*uView*uModel*vec4(vPosition, 1.0);
318                 inVertexColor = vColor;
319                 inTexST = vTexST;
320                 inTexID = vTexID;
321             }
322         }.fastUnsafeCTFEFormat(attr1, attr2, attr3, attr4, out1, out2, out3);
323         return shaderVersion~"\n"~floatPrecision~"\n"~shaderSource;
324     }
325     override final string getGeometryBatchVertex()
326     {
327         version(GLES20)
328         {
329             enum attr1 = q{attribute};
330             enum attr2 = q{attribute};
331             enum out1 = q{varying};
332         }
333         else
334         {
335             enum attr1 = q{layout (location = 0) in};
336             enum attr2 = q{layout (location = 1) in};
337             enum out1 = q{out};
338         }
339 
340         enum shaderSource = q{
341             
342             %s vec3 vPosition;
343             %s vec4 vColor;
344 
345             uniform mat4 uProj;
346             uniform mat4 uModel;
347             uniform mat4 uView;
348             
349             %s vec4 inVertexColor;
350 
351             void main()
352             {
353                 gl_Position = uProj*uView*uModel*vec4(vPosition, 1.0);
354                 inVertexColor = vColor;
355             }
356         }.fastUnsafeCTFEFormat(attr1, attr2, out1);
357         return shaderVersion~"\n"~floatPrecision~"\n"~shaderSource;
358     }
359 
360     override final string getBitmapTextVertex()
361     {
362         version(GLES20)
363         {
364             enum attr1 = q{attribute};
365             enum attr2 = q{attribute};
366             enum out1 = q{varying};
367         }
368         else
369         {
370             enum attr1 = q{layout (location = 0) in};
371             enum attr2 = q{layout (location = 1) in};
372             enum out1 = q{out};
373         }
374         enum shaderSource = q{
375             
376             %s vec2 vPosition;
377             %s vec2 vTexST;
378 
379             uniform mat4 uModel;
380             uniform mat4 uView;
381             uniform mat4 uProj;
382 
383             %s vec2 inTexST;
384 
385             void main()
386             {
387                 gl_Position = uProj * uView * uModel * vec4(vPosition, 1.0, 1.0);
388                 inTexST = vTexST;
389             }
390         }.fastUnsafeCTFEFormat(attr1, attr2, out1);
391         return shaderVersion~"\n"~floatPrecision~"\n"~shaderSource;
392     }
393 }
394 class Hip_GL3_ShaderProgram : ShaderProgram
395 {
396     bool isUsingUbo;
397     uint program;
398     protected HipBlendFunction blendSrc = HipBlendFunction.CONSTANT_COLOR, blendDst = HipBlendFunction.CONSTANT_COLOR;
399     protected HipBlendEquation blendEq = HipBlendEquation.DISABLED;
400 }
401 
402 
403 GLenum getGLBlendFunction(HipBlendFunction func)
404 {
405     final switch(func) with(HipBlendFunction)
406     {
407         case  ZERO: return GL_ZERO;
408         case  ONE: return GL_ONE;
409         case  SRC_COLOR: return GL_SRC_COLOR;
410         case  ONE_MINUS_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR;
411         case  DST_COLOR: return GL_DST_COLOR;
412         case  ONE_MINUS_DST_COLOR: return GL_ONE_MINUS_DST_COLOR;
413         case  SRC_ALPHA: return GL_SRC_ALPHA;
414         case  ONE_MINUS_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA;
415         case  DST_ALPHA: return GL_DST_ALPHA;
416         case  ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA;
417         case  CONSTANT_COLOR: return GL_CONSTANT_COLOR;
418         case  ONE_MINUS_CONSTANT_COLOR: return GL_ONE_MINUS_CONSTANT_COLOR;
419         case  CONSTANT_ALPHA: return GL_CONSTANT_ALPHA;
420         case  ONE_MINUS_CONSTANT_ALPHA: return GL_ONE_MINUS_CONSTANT_ALPHA;
421     }
422 }
423 GLenum getGLBlendEquation(HipBlendEquation eq)
424 {
425     final switch(eq) with (HipBlendEquation)
426     {
427         case DISABLED: return GL_FUNC_ADD;
428         case ADD: return GL_FUNC_ADD;
429         case SUBTRACT: return GL_FUNC_SUBTRACT;
430         case REVERSE_SUBTRACT: return GL_FUNC_REVERSE_SUBTRACT;
431         case MIN: return GL_MIN;
432         case MAX: return GL_MAX;
433     }
434 }
435 class Hip_GL_ShaderImpl : IShader
436 {
437     import hip.util.data_structures:Pair;
438     protected ShaderVariablesLayout[] layouts;
439     FragmentShader createFragmentShader()
440     {
441         Hip_GL3_FragmentShader fs = new Hip_GL3_FragmentShader();
442         fs.shader = glCreateShader(GL_FRAGMENT_SHADER);
443         HipRenderer.exitOnError();
444         return fs;
445     }
446 
447     VertexShader createVertexShader()
448     {
449         Hip_GL3_VertexShader vs = new Hip_GL3_VertexShader();
450         vs.shader = glCreateShader(GL_VERTEX_SHADER);
451         HipRenderer.exitOnError();
452         return vs;
453     }
454     ShaderProgram createShaderProgram()
455     {
456         Hip_GL3_ShaderProgram prog = new Hip_GL3_ShaderProgram();
457         prog.program = glCreateProgram();
458         HipRenderer.exitOnError();
459         return prog;
460     }
461     bool compileShader(GLuint shaderID, string shaderSource)
462     {
463         shaderSource~="\0";
464         char* source = cast(char*)shaderSource.ptr; 
465         glCall(() =>glShaderSource(shaderID, 1, &source,  cast(GLint*)null));
466         glCall(() =>glCompileShader(shaderID));
467         int success;
468         
469         glCall(() => glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success));
470         if(ErrorHandler.assertErrorMessage(success==true, "Shader compilation error", "Compilation failed"))
471         {
472             import core.stdc.stdlib;
473             char[] infoLog;
474             version(WebAssembly)
475             {
476                 {
477                     GLint length = 0;
478                     ubyte* temp = glCall(() => wglGetShaderInfoLog(shaderID));
479                     length = *cast(GLint*)temp;
480                     infoLog = cast(char[])temp[size_t.sizeof..+size_t.sizeof + length];
481                 }
482             }
483             else
484             {
485                 {
486                     GLint length = 0;
487                     glCall(() => glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &length));
488                     infoLog = cast(char[])malloc(length)[0..length];
489                     glCall(() =>glGetShaderInfoLog(shaderID, length, &length, infoLog.ptr));
490                 }
491             }
492             ErrorHandler.showErrorMessage("Error on shader source: ", shaderSource);
493             ErrorHandler.showErrorMessage("Compilation error:", cast(string)(infoLog));
494             version(WebAssembly)
495                 free(infoLog.ptr - GLint.sizeof); //Remember that the pointer started in length.
496             else
497                 free(infoLog.ptr);
498         }
499         return success==true;
500     }
501     bool compileShader(VertexShader vs, string shaderSource)
502     {
503         return compileShader((cast(Hip_GL3_VertexShader)vs).shader, shaderSource);
504     }
505     bool compileShader(FragmentShader fs, string shaderSource)
506     {
507         return compileShader((cast(Hip_GL3_FragmentShader)fs).shader, shaderSource);
508     }
509 
510     bool linkProgram(ref ShaderProgram program, VertexShader vs,  FragmentShader fs)
511     {
512         uint prog = (cast(Hip_GL3_ShaderProgram)program).program;
513 
514         glCall(() =>glAttachShader(prog, (cast(Hip_GL3_VertexShader)vs).shader));
515         glCall(() =>glAttachShader(prog, (cast(Hip_GL3_FragmentShader)fs).shader));
516         glCall(() =>glLinkProgram(prog));
517         
518         int success;
519         char[512] infoLog;
520 
521         glCall(() =>glGetProgramiv(prog, GL_LINK_STATUS, &success));
522 
523         if(ErrorHandler.assertErrorMessage(success==true, "Shader linking error", "Linking failed"))
524         {
525             glCall(() => glGetProgramInfoLog(prog, 512, null, infoLog.ptr));
526             ErrorHandler.showErrorMessage("Linking error: ", cast(string)(infoLog));
527         }
528         
529         return success==true;
530     }
531     int getId(ref ShaderProgram prog, string name)
532     {
533         int varID = glCall(() =>glGetUniformLocation((cast(Hip_GL3_ShaderProgram)prog).program, cast(char*)name.ptr)); //Immutable anyway
534         if(varID < 0)
535         {
536             ErrorHandler.showErrorMessage("Uniform not found",
537             "Variable named '"~name~"' does not exists in shader "~prog.name);
538         }
539         return varID;
540     }
541     
542 
543     /**
544     *   params:
545     *       layoutIndex: The layout index defined on shader
546     *       valueAmount: How many values using, for 3 vertices, you can use 3
547     *       dataType: Which data type to send
548     *       normalize: If it will normalize
549     *       stride: Target value amount in bytes, for instance, vec3 is float.sizeof*3
550     *       offset: It will be calculated for each value index
551     *       
552     */
553     void sendVertexAttribute(uint layoutIndex, int valueAmount, uint dataType, bool normalize, uint stride, int offset)
554     {
555         glCall(() =>glVertexAttribPointer(layoutIndex, valueAmount, dataType, normalize, stride, cast(void*)offset));
556         glCall(() =>glEnableVertexAttribArray(layoutIndex));
557     }
558 
559     private __gshared Hip_GL_ShaderImpl boundShader;
560     private __gshared HipBlendFunction currSrc, currDst;
561     private __gshared HipBlendEquation currEq;
562     private __gshared blendingEnabled = false;
563 
564     public void setBlending(ShaderProgram prog, HipBlendFunction src, HipBlendFunction dst, HipBlendEquation eq)
565     {
566         Hip_GL3_ShaderProgram p = cast(Hip_GL3_ShaderProgram)prog;
567         p.blendSrc = src;
568         p.blendDst = dst;
569         p.blendEq = eq;
570     }
571 
572     void bind(ShaderProgram program)
573     {
574         if(boundShader !is this)
575         {
576             Hip_GL3_ShaderProgram p = cast(Hip_GL3_ShaderProgram)program;
577             if(p.blendEq == HipBlendEquation.DISABLED)
578             {
579                 if(blendingEnabled)
580                 {
581                     glCall(() => glDisable(GL_BLEND));
582                     blendingEnabled = false;
583                 }
584             }
585             else
586             {
587                 if(!blendingEnabled)
588                 {
589                     glCall(() => glEnable(GL_BLEND));
590                     blendingEnabled = true;
591                 }
592                 if(currEq != p.blendEq)
593                 {
594                     currEq = p.blendEq;
595                     glCall(() => glBlendEquation(getGLBlendEquation(p.blendEq)));
596                 }
597                 if(currSrc != p.blendSrc || currDst != p.blendDst)
598                 {
599                     currSrc = p.blendSrc;
600                     currDst = p.blendDst;
601                     glCall(() => glBlendFunc(getGLBlendFunction(p.blendSrc), getGLBlendFunction(p.blendDst)));
602                 }
603             }
604             glCall(() =>glUseProgram(p.program));
605             boundShader = this;
606         }
607     }
608     void unbind(ShaderProgram program)
609     {
610         if(boundShader is this)
611         {
612             glCall(() =>glUseProgram(0));
613             boundShader = null;
614         }
615     }
616 
617     void sendVars(ref ShaderProgram prog, ShaderVariablesLayout[string] layouts)
618     {
619         foreach(ShaderVariablesLayout l; layouts)
620         {
621             foreach (ref ShaderVarLayout v; l.variables)
622             {
623                 if(!v.sVar.isDirty)
624                     continue;
625                 int id = getId(prog, v.sVar.name);
626                 final switch(v.sVar.type) with(UniformType)
627                 {
628                     case boolean:
629                         glCall(() => glUniform1i(id, v.sVar.get!bool));
630                         break;
631                     case integer:
632                         glCall(() => glUniform1i(id, v.sVar.get!int));
633                         break;
634                     case integer_array:
635                         int[] temp = v.sVar.get!(int[]);
636                         glCall(() =>glUniform1iv(id, cast(int)temp.length, temp.ptr));
637                         break;
638                     case uinteger:
639                         glCall(() =>glUniform1ui(id, v.sVar.get!uint));
640                         break;
641                     case uinteger_array:
642                         uint[] temp = v.sVar.get!(uint[]);
643                         glCall(() =>glUniform1uiv(id, cast(int)temp.length, temp.ptr));
644                         break;
645                     case floating:
646                         glCall(() =>glUniform1f(id, v.sVar.get!float));
647                         break;
648                     case floating2:
649                         float[2] temp = v.sVar.get!(float[2]);
650                         glCall(() =>glUniform2f(id, temp[0], temp[1]));
651                         break;
652                     case floating3:
653                         float[3] temp = v.sVar.get!(float[3]);
654                         glCall(() =>glUniform3f(id, temp[0], temp[1], temp[2]));
655                         break;
656                     case floating4:
657                         float[4] temp = v.sVar.get!(float[4]);
658                         glCall(() =>glUniform4f(id, temp[0], temp[1], temp[2], temp[3]));
659                         break;
660                     case floating2x2:
661                         glCall(() => glUniformMatrix2fv(id, 1, GL_FALSE, cast(float*)v.sVar.get!(float[4]).ptr));
662                         break;
663                     case floating3x3:
664                         glCall(() =>glUniformMatrix3fv(id, 1, GL_FALSE, cast(float*)v.sVar.get!(float[9]).ptr));
665                         break;
666                     case floating4x4:
667                         glCall(() => glUniformMatrix4fv(id, 1, GL_FALSE, cast(float*)v.sVar.get!(float[16]).ptr));
668                         break;
669                     case floating_array:
670                         float[] temp = v.sVar.get!(float[]);
671                         glCall(() => glUniform1fv(id, cast(int)temp.length, temp.ptr));
672                         break;
673                     case texture_array:
674                         GLint[] temp = v.sVar.get!(GLint[]);
675                         glCall(() => glUniform1iv(id, cast(int)temp.length, cast(int*)temp.ptr));
676                         break;
677                     case none:break;
678                 }
679                 v.sVar.isDirty = false;
680             }
681         }
682                 
683     }
684 
685     bool setShaderVar(ShaderVar* sv, ShaderProgram prog, void* value)
686     {
687         ///Optimization for not allocating when inside loops.
688         __gshared int[] temp;
689         switch(sv.type) with(UniformType)
690         {
691             case texture_array:
692             {
693                 IHipTexture[] textures = *cast(IHipTexture[]*)value;
694                 if(textures.length > temp.length)
695                     temp.length = textures.length;
696                 int length = cast(int)textures.length;
697                 foreach(i; 0..length)
698                     temp[i] = i;
699                 sv.set(temp, false);
700                 return true;
701             }
702             default: return false;
703         }
704     }
705 
706     void bindArrayOfTextures(ref ShaderProgram prog, IHipTexture[] textures, string varName)
707     {
708         bool shouldControlBind = boundShader !is this;
709 
710         if(shouldControlBind)
711             bind(prog);
712         
713         foreach(int i; 0..cast(int)textures.length)
714             textures[i].bind(i);
715         if(shouldControlBind)
716             unbind(prog);
717     }
718     void createVariablesBlock(ref ShaderVariablesLayout layout)
719     {
720         if(layout.hint & ShaderHint.GL_USE_BLOCK)
721             ErrorHandler.assertExit(false, "Use HipGL3 for Uniform Block support.");
722     }
723 
724     void deleteShader(FragmentShader* _fs)
725     {
726         auto fs = cast(Hip_GL3_FragmentShader)*_fs;
727         glCall(() => glDeleteShader(fs.shader)); fs.shader = 0;
728     }
729     void deleteShader(VertexShader* _vs)
730     {
731         auto vs = cast(Hip_GL3_VertexShader)*_vs;
732         glCall(() => glDeleteShader(vs.shader)); vs.shader = 0;
733     }
734     void dispose(ref ShaderProgram prog)
735     {
736         Hip_GL3_ShaderProgram p = cast(Hip_GL3_ShaderProgram)prog;
737         glCall(() => glDeleteProgram(p.program));
738     }
739     void onRenderFrameEnd(ShaderProgram program){}
740 }
741 
742 
743 version(HipGL3) class Hip_GL3_ShaderImpl : Hip_GL_ShaderImpl
744 {
745     import hip.util.data_structures:Pair;
746     protected Pair!(ShaderVariablesLayout, uint)[] ubos;
747 
748     override int getId(ref ShaderProgram prog, string name)
749     {
750         // auto glProg = cast(Hip_GL3_ShaderProgram)prog;
751         //if(glProg.isUsingUbo)
752           //  return getUboId()
753         //else
754         return super.getId(prog, name);
755     }
756 
757     override void createVariablesBlock(ref ShaderVariablesLayout layout)
758     {
759         if(layout.hint & ShaderHint.GL_USE_BLOCK)
760         {
761             uint ubo;
762             glCall(() => glGenBuffers(1, &ubo));
763             glCall(() => glBindBuffer(GL_UNIFORM_BUFFER, ubo));
764             glCall(() => glBufferData(GL_UNIFORM_BUFFER, layout.getLayoutSize(), null, GL_DYNAMIC_DRAW));
765             glCall(() => glBindBuffer(GL_UNIFORM_BUFFER, 0));
766             ubos~= Pair!(ShaderVariablesLayout, uint)(layout, ubo);
767         }
768     }
769     protected uint getUboId(ref Pair!(ShaderVariablesLayout, int) ubo, string name)
770     {
771         return glCall(() =>glGetUniformBlockIndex(ubo.b, cast(char*)name.ptr));
772     }
773     protected void bindUbo(ref Pair!(ShaderVariablesLayout, int) ubo, int index = 0)
774     {
775         glCall(() =>glBindBufferBase(GL_UNIFORM_BUFFER, index, ubo.second));
776     }
777     protected void updateUbo(ref Pair!(ShaderVariablesLayout, int) ubo)
778     {
779         import core.stdc.string;
780         glCall(() =>glBindBuffer(GL_UNIFORM_BUFFER, ubo.b));
781         GLvoid* ptr = glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY);
782         memcpy(ptr, ubo.a.getBlockData(), ubo.a.getLayoutSize());
783         glCall(() => glUnmapBuffer(GL_UNIFORM_BUFFER));
784         glCall(() => glBindBuffer(GL_UNIFORM_BUFFER, 0));
785     }
786     
787 
788 
789     override void sendVars(ref ShaderProgram prog, ShaderVariablesLayout[string] layouts)
790     {
791         Hip_GL3_ShaderProgram glProg = cast(Hip_GL3_ShaderProgram)prog;
792         if(!glProg.isUsingUbo)
793         {
794             super.sendVars(prog, layouts);
795             return;
796         }
797         assert(false, "UBO binding is still not in use.");
798     }
799 
800     override void dispose(ref ShaderProgram prog)
801     {
802         foreach (ub; ubos)
803             glCall(() => glDeleteBuffers(1, &ub.b));
804         ubos.length = 0;
805         super.dispose(prog);
806     }
807 }